#include <iostream>
#include <dlfcn.h>

#include "include/DllManager.h"
#include "include/Manager.h"
#include "include/Singleton.h"
#include "include/Configuration.h"

void DllManager::Init()
{
	_current_dll = 0;
	_right_dll = 1;
	_dll_handle = NULL;
}

int DllManager::LoadDll(int thread_id)
{
	std::cout << "enter load dll " << std::endl;

	_right_dll = Singleton<Manager>::instance().dll_state;

	if(_current_dll == _right_dll)
	{
		return 0;
	}

	UnloadDll(thread_id);

	if(1 == _right_dll)
	{
		// debug
		std::cout << "start load dll 1" << std::endl;
		// debug end
		_dll_handle = dlopen(Singleton<Configuration>::instance().first_dll_path.c_str(), RTLD_LAZY);
		if(NULL == _dll_handle)
		{
			// debug
			std::cout << "open dll 1 Error" << std::endl;
			std::cout << dlerror() << std::endl;
			// debug end
			return 1;
		}

		dlerror();

		*(void **)(&DllInit) = dlsym(_dll_handle, Singleton<Configuration>::instance().dll_init_func.c_str());
		if(NULL != dlerror())
		{
			// debug
			std::cout << "get dll init Error" << std::endl;
			// debug end
			UnloadDll(thread_id);
			return 1;
		}

		*(void **)(&Do) = dlsym(_dll_handle, Singleton<Configuration>::instance().first_dll_func.c_str());
		if(NULL != dlerror())
		{
			// debug
			std::cout << "get dll main Error" << std::endl;
			// debug end
			UnloadDll(thread_id);
			return 1;
		}

		*(void **)(&DllExit) = dlsym(_dll_handle, Singleton<Configuration>::instance().dll_exit_func.c_str());
		if(NULL != dlerror())
		{
			// debug
			std::cout << "get dll exit Error" << std::endl;
			// debug end
			UnloadDll(thread_id);
			return 1;
		}

		_current_dll = 1;
	}
	else
	{
		_dll_handle = dlopen(Singleton<Configuration>::instance().second_dll_path.c_str(), RTLD_LAZY);
		if(NULL == _dll_handle)
		{
			return 1;
		}

		dlerror();

		*(void **)(&DllInit) = dlsym(_dll_handle, Singleton<Configuration>::instance().dll_init_func.c_str());
		if(NULL != dlerror())
		{
			UnloadDll(thread_id);
			return 1;
		}

		*(void **)(&Do) = dlsym(_dll_handle, Singleton<Configuration>::instance().second_dll_func.c_str());
		if(NULL != dlerror())
		{
			UnloadDll(thread_id);
			return 1;
		}

		*(void **)(&DllExit) = dlsym(_dll_handle, Singleton<Configuration>::instance().dll_exit_func.c_str());
		if(NULL != dlerror())
		{
			UnloadDll(thread_id);
			return 1;
		}

		_current_dll = 2;
	}

	DllInit(Singleton<Configuration>::instance().game_config_file.c_str(), thread_id);

	return 0;
}

void DllManager::UnloadDll(int thread_id)
{
	if(NULL == _dll_handle)
	{
		return;
	}

	DllExit(thread_id);
	dlclose(_dll_handle);
	_dll_handle = NULL;
}
